﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace PostProcessing
{
    [Serializable]
    public class Taxonomy
    {
        public TaxonomyNode cabeca;

        public Taxonomy(){}
        public Taxonomy(string cabeca)
        {
            this.cabeca = new TaxonomyNode(cabeca, null);
        }

        /// <summary>
        /// Adiciona um item na taxonomia.
        /// </summary>
        /// <param name="pai">Pai do item que será adicionado. Se for nulo, adiciona o item como filho do nó cabeça.</param>
        /// <param name="valor">Item a adicionar.</param>
        public void addNode(string pai, string valor)
        {
            TaxonomyNode nodePai;

            if (valor != "" && valor != null)
            {
                //Se ainda não existe um cabeça, elege este novo nó como cabeça.
                if (cabeca == null)
                    cabeca = new TaxonomyNode(valor, null);
                else
                {
                    //Se foi informado um pai, procura-o na taxonomia e adiciona o filho. Se não foi informado um pai, adiciona filho no cabeça.
                    if ((pai != null) && (pai != ""))
                    {
                        nodePai = pertence(pai, null);

                        if (nodePai == null)
                        {
                            throw new Exception("Pai inexistente na taxonomia " + cabeca.valor);
                        }
                        else
                        {
                            nodePai.addFilho(valor);
                        }
                    }
                    else
                        cabeca.addFilho(valor);
                }
            }
        }

        /// <summary>
        /// Remove um determinado item desta taxonomia.
        /// </summary>
        /// <param name="node"></param>
        public void removeNode(string node)
        {
            TaxonomyNode taxNode = pertence(node, null);
            TaxonomyNode paiTaxNode;

            if (taxNode != null)
            {
                paiTaxNode = taxNode.pai;
                paiTaxNode.filhos.Remove(taxNode);
            }
            else
                throw new Exception("Item inexistente. Impossível remover.");

            GC.Collect();
        }

        /// <summary>
        /// Método recursivo que verifica se um determinado valor pertence à esta taxonomia.
        /// </summary>
        /// <param name="valor">Item a ser procurado.</param>
        /// <param name="noInicial">Geralmente este parâmetro é nulo. Existe para uso com a recursão.</param>
        /// <returns>Retorna o nó da taxonomia ou nulo se o valor não pertence à taxonomia.</returns>
        public TaxonomyNode pertence(string valor, TaxonomyNode noInicial)
        {
            TaxonomyNode node;

            if (noInicial != null)
                node = noInicial;
            else
                node = cabeca;

            //Se o valor deste nó não for o valor procurado...
            if (node.valor != valor)
            {
                //Procura o valor nos filhos deste nó.
                if (node.filhos.Count > 0)
                {
                    TaxonomyNode nodeResult;

                    foreach (TaxonomyNode filho in node.filhos)
                    {
                        nodeResult = pertence(valor, filho);

                        if (nodeResult != null)
                            return nodeResult;
                    }
                }
            }
            else
                return node;

            return null;
        }

        /// <summary>
        /// Gera uma árvore para ser utilizada com o controle TreeView, contendo esta taxonomia.
        /// </summary>
        /// <param name="currentNode"></param>
        /// <returns></returns>
        public TreeNode gerarTreeViewNode(TaxonomyNode currentNode)
        {
            if (currentNode == null)
                currentNode = cabeca;

            TreeNode treeNode = new TreeNode(currentNode.valor);

            foreach (TaxonomyNode filho in currentNode.filhos)
            {
                treeNode.Nodes.Add(gerarTreeViewNode(filho));
            }

            return treeNode;
        }
    }

    [Serializable]
    public class TaxonomyNode
    {
        public string valor;
        public TaxonomyNode pai;
        public List<TaxonomyNode> filhos;

        public TaxonomyNode()
        {
            filhos = new List<TaxonomyNode>();
        }

        public TaxonomyNode(string valor, TaxonomyNode pai)
        {
            this.valor = valor;
            this.pai = pai;
            filhos = new List<TaxonomyNode>();
        }

        public void addFilho(string valor)
        {
            filhos.Add(new TaxonomyNode(valor, this));
        }
    }
}
